home *** CD-ROM | disk | FTP | other *** search
/ EnigmA Amiga Run 1997 April / EnigmA AMIGA RUN 17 (1997)(G.R. Edizioni)(IT)[!][issue 1997-04][EAR-CD].iso / EARCD / text / hyper / hsc_source.lha / hsc / source / ugly / umemory.c < prev    next >
C/C++ Source or Header  |  1996-11-15  |  16KB  |  645 lines

  1. /*
  2.  * ugly/umemory.c
  3.  *
  4.  * additional memory manegment functions;
  5.  * implements some parts of Amiga-developer-tool
  6.  * "MungWall" at source-level
  7.  *
  8.  * Copyright (C) 1994,95,96  Thomas Aglassinger
  9.  *
  10.  * This program is free software; you can redistribute it and/or modify
  11.  * it under the terms of the GNU General Public License as published by
  12.  * the Free Software Foundation; either version 2 of the License, or
  13.  * (at your option) any later version.
  14.  *
  15.  * This program is distributed in the hope that it will be useful,
  16.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  17.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  18.  * GNU General Public License for more details.
  19.  *
  20.  * You should have received a copy of the GNU General Public License
  21.  * along with this program; if not, write to the Free Software
  22.  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  23.  *
  24.  * updated: 13-Sep-1996
  25.  * created: 29-Mar-1994
  26.  *
  27.  */
  28.  
  29. /*
  30.  *
  31.  * Memory munging:
  32.  *
  33.  *   Except for ucalloc(), memory is pre-munged on allocation with
  34.  *   $DEADFOOD. When this is used in an Enforcer report, the caller is
  35.  *   allocating memory and doesn't initialize it before using it.
  36.  *
  37.  *   Memory is filled with $DEADBEEF before it is freed, encouraging
  38.  *   programs reusing free'ed memory to crash.
  39.  *
  40.  * Memory watching:
  41.  *
  42.  *   Null sized malloc()'s are reported. The integrity of the walls will
  43.  *   be tested according to the size specified when free'ed.
  44.  *
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include <stdlib.h>
  49. #include <string.h>
  50.  
  51. #include "utypes.h"
  52.  
  53. #define NOEXTERN_UGLY_UMEMORY_H
  54. #include "umemory.h"
  55.  
  56. /*
  57.  * size of wall build around every memory block
  58.  */
  59. #define UMEM_WALLSIZE 16
  60. /*
  61.  * blocksize memory allocations are rounded up by OS
  62.  * (this one's only needed to compute the amount of
  63.  * slack-memory and won't cause any problems if wrong)
  64.  */
  65. #if defined(AMIGA)
  66. #define UMEM_BLOCKSIZE 8        /* AmigaOS */
  67. #else
  68. #define UMEM_BLOCKSIZE 8
  69. #endif
  70.  
  71. #ifndef modfit
  72. #define modfit(x,by) ((by)*(((x)+(by-1))/(by)))
  73. #endif
  74.  
  75. static UGLYMEM *first = NULL;
  76.  
  77. static UBYTE deadbeef[4] =
  78. {0xDE, 0xAD, 0xBE, 0xEF};       /* used to fill mem after free() */
  79. static UBYTE deadfood[4] =
  80. {0xDE, 0xAD, 0xF0, 0x0D};       /* used to fill mem after malloc() */
  81.  
  82. static UBYTE ugly_fillchar = 0x81;
  83.  
  84. static ULONG ugly_umalloc_count = 0;    /* num. of calls to umalloc()/ucalloc() */
  85. static ULONG ugly_ufree_count = 0;      /* num. of calls to ufree() */
  86. static ULONG ugly_umalloc_count_fail = 0;       /* num. of failed calls to umalloc() */
  87. static ULONG ugly_ufree_count_fail = 0;         /* num. of failed calls to ufree() */
  88. static ULONG ugly_maxmem_usage = 0;     /* maximum memmory used */
  89. static ULONG ugly_curmem_usage = 0;     /* current memory used */
  90. static ULONG ugly_real_maxmem_usage = 0;        /* maximum memmory used */
  91. static ULONG ugly_real_curmem_usage = 0;        /* current memory used */
  92. static ULONG ugly_maxnod_usage = 0;     /* maximum num. of memmory nodes used */
  93. static ULONG ugly_curnod_usage = 0;     /* current num. of memory nodes used */
  94.  
  95. /* forward reference */
  96. void *ugly_malloc_notracking(size_t size);
  97. static BOOL ugly_walldamaged(UGLYMEM * umem);
  98.  
  99. /* function pointer for nomem-handler */
  100. BOOL(*ugly_nomem_handler) (size_t size) = NULL;
  101.  
  102. /*
  103.  * find_umem
  104.  */
  105. static UGLYMEM *find_umem(void *mem)
  106. {
  107.     UGLYMEM *nxtum = first;
  108.     UGLYMEM *found = NULL;
  109.  
  110.     while (nxtum && (!found)) {
  111.  
  112.         if (nxtum->ptr == mem)
  113.             found = nxtum;
  114.         nxtum = nxtum->next;
  115.  
  116.     }
  117.  
  118. #if DEBUG_UGLY_MEMORY==2
  119.     if (!found) {
  120.         fprintf(stderr, "*memory* FIND_UMEM: couln't find %p\n", mem);
  121.     }
  122. #endif
  123.  
  124.     return (found);
  125. }
  126.  
  127. /*
  128.  * find_prev
  129.  */
  130. static UGLYMEM *find_prev(UGLYMEM * umem)
  131. {
  132.     UGLYMEM *prev = first;
  133.     UGLYMEM *pprev = NULL;
  134.     BOOL found = FALSE;
  135.  
  136.     while (prev && (!found)) {
  137.         found = (prev == umem);
  138.         if (!found) {
  139.             pprev = prev;
  140.             prev = prev->next;
  141.         }
  142.     }
  143.  
  144.     return (pprev);
  145. }
  146.  
  147. /*
  148.  * fill_mem4, fill_mem
  149.  *
  150.  * fill memory with value specified
  151.  */
  152. static void fill_mem4(void *mem, size_t size, UBYTE value[4])
  153. {
  154.     size_t i;
  155.  
  156.     for (i = 0; i < size; i++)
  157.         (((UBYTE *) mem)[i]) = value[i % 4];
  158. }
  159.  
  160. static void fill_mem(void *mem, size_t size, UBYTE value)
  161. {
  162.     size_t i;
  163.  
  164.     for (i = 0; i < size; i++)
  165.         (((UBYTE *) mem)[i]) = value;
  166. }
  167.  
  168. /*
  169.  * del_uglymem
  170.  *
  171.  * free an uglymem-entry
  172.  */
  173. static void del_uglymem(UGLYMEM * umem)
  174. {
  175.     UGLYMEM *prev = find_prev(umem);
  176.  
  177.     /* unlink from list */
  178.     if (prev) {
  179.         prev->next = umem->next;
  180.     } else {
  181.         first = umem->next;
  182.     }
  183.  
  184.     /* check for damaged wall */
  185.     if (!ugly_walldamaged(umem)) {
  186.  
  187.         /* wall ok:
  188.          *
  189.          * fill memory with $DEADBEEF,
  190.          * free memory */
  191.         fill_mem4(umem->lower, umem->size + 2 * UMEM_WALLSIZE, deadbeef);
  192.         free(umem->lower);
  193.  
  194.     }
  195.     /* free memory structure */
  196.     umem->lower = NULL;
  197.     umem->upper = NULL;
  198.     umem->size = 0;
  199.     umem->file = NULL;
  200.     umem->line = 0;
  201.     free(umem);
  202. }
  203.  
  204. /*
  205.  * new uglymem
  206.  *
  207.  * alloc & init a new entry of ugly mem
  208.  */
  209. static UGLYMEM *new_uglymem(size_t memsize, STRPTR memfile, ULONG memline)
  210. {
  211.     UGLYMEM *newmem = (UGLYMEM *) malloc(sizeof(UGLYMEM));
  212.  
  213.     if (newmem) {
  214.  
  215.         newmem->lower = (STRPTR) ugly_malloc_notracking(memsize
  216.                                                         + 2 * UMEM_WALLSIZE);
  217.         if (newmem->lower) {
  218.  
  219.             /* compute location of main mem/upper wall */
  220.             newmem->ptr = (void *) (newmem->lower + UMEM_WALLSIZE);
  221.             newmem->upper = (newmem->lower + UMEM_WALLSIZE + memsize);
  222.  
  223.             /* link to list */
  224.             newmem->next = first;
  225.             first = newmem;
  226.  
  227.             /* init data */
  228.             newmem->size = memsize;
  229.             newmem->file = memfile;
  230.             newmem->line = memline;
  231.             newmem->fillchar = ugly_fillchar;
  232.  
  233.             /* fill new mem area with $DEADF00D */
  234.             fill_mem4(newmem->ptr, memsize, deadfood);
  235.  
  236.             /* fill lower/upper wall */
  237.             fill_mem(newmem->lower, UMEM_WALLSIZE, ugly_fillchar);
  238.             fill_mem(newmem->upper, UMEM_WALLSIZE, ugly_fillchar);
  239.  
  240.             /* update fillchar */
  241.             if (ugly_fillchar == 0xff)
  242.                 ugly_fillchar = 0x81;
  243.             else
  244.                 ugly_fillchar++;
  245.  
  246.         } else
  247.             free(newmem);
  248.     }
  249.     return (newmem);
  250. }
  251.  
  252. static void uglymem_message(STRPTR msg)
  253. {
  254.     fprintf(stderr, "%s\n", msg);
  255. }
  256.  
  257. static void ugly_memdump(void *ptr, size_t size)
  258. {
  259.     STRPTR data = (STRPTR) ptr;
  260.  
  261.     /* limit size */
  262.     if (size > 16)
  263.         size = 16;
  264.  
  265.     fprintf(stderr, "  %p:", ptr);
  266.     if (data) {
  267.  
  268.         size_t i;
  269.  
  270.         /* hex dump */
  271.         for (i = 0; i < size; i++) {
  272.  
  273.             if (!(i % 4))
  274.                 fprintf(stderr, " ");
  275.             fprintf(stderr, "%02x", data[i]);
  276.  
  277.         }
  278.  
  279.         /* fill with blanks */
  280.         while (i < 16) {
  281.  
  282.             if (!(i % 4))
  283.                 fprintf(stderr, " ");
  284.             fprintf(stderr, "  ");
  285.             i++;
  286.         }
  287.  
  288.         fprintf(stderr, "  \"");
  289.         /* ascii dump */
  290.         for (i = 0; i < size; i++)
  291.             if (data[i] < ' ')
  292.                 fprintf(stderr, ".");
  293.             else
  294.                 fprintf(stderr, "%c", data[i]);
  295.         fprintf(stderr, "\"\n");
  296.  
  297.     } else
  298.         fprintf(stderr, "NULL\n");
  299.  
  300. }
  301.  
  302. static void uglymem_meminfo(void *ptr, STRPTR file, ULONG line)
  303. {
  304.     fprintf(stderr, "  %p: from \"%s\" (%lu)\n", ptr, file, line);
  305. }
  306.  
  307. static void umem_info(UGLYMEM * umem)
  308. {
  309.     fprintf(stderr, "  %p: %lu (0x%lx) bytes from \"%s\" (%lu)\n",
  310.             umem->ptr, (ULONG) umem->size, (ULONG) umem->size,
  311.             umem->file, umem->line);
  312. }
  313.  
  314. /*
  315.  *-------------------------------------
  316.  * wall check functions
  317.  *-------------------------------------
  318.  */
  319.  
  320. static STRPTR str_ubyte(UBYTE val)
  321. {
  322.     static STRARR strbuf[30];
  323.     UBYTE ch = val;
  324.  
  325.     if (ch < 32)
  326.         ch = '.';
  327.  
  328.     sprintf(strbuf, "(0x%02x/#%d/`%c')", val, val, ch);
  329.  
  330.     return (strbuf);
  331. }
  332.  
  333. static BOOL ugly_walldamaged(UGLYMEM * umem)
  334. {
  335.     size_t i = 0;
  336.     BOOL damaged = FALSE;
  337.  
  338.     while (!damaged && (i < UMEM_WALLSIZE)) {
  339.  
  340.         BOOL lower_damaged = (umem->lower[i] != umem->fillchar);
  341.         BOOL upper_damaged = (umem->upper[i] != umem->fillchar);
  342.  
  343.         damaged = lower_damaged || upper_damaged;
  344.         if (damaged) {
  345.  
  346.             STRPTR wall;
  347.             UBYTE value;
  348.  
  349.             if (lower_damaged) {
  350.                 wall = "LOWER";
  351.                 value = umem->lower[i];
  352.             } else {
  353.                 wall = "UPPER";
  354.                 value = umem->upper[i];
  355.             }
  356.  
  357.             fprintf(stderr, "*** MEMORY WALL DAMAGED!!!\n");
  358.             fprintf(stderr, "*** %s wall, byte#%lu is %s instead of 0x%02x\n",
  359.                     wall, (ULONG) i, str_ubyte(value), umem->fillchar);
  360.             umem_info(umem);
  361.             ugly_memdump(umem->ptr, umem->size);
  362.             fprintf(stderr, "  * lower wall:\n");
  363.             ugly_memdump(umem->lower, UMEM_WALLSIZE);
  364.             fprintf(stderr, "  * upper wall:\n");
  365.             ugly_memdump(umem->upper, UMEM_WALLSIZE);
  366.  
  367.         } else
  368.             i++;
  369.  
  370.     }
  371.  
  372.     return (damaged);
  373. }
  374.  
  375. void uglymem_wallcheck(STRPTR msg, STRPTR file, ULONG line)
  376. {
  377.     UGLYMEM *umem = first;
  378.  
  379.     if (umem) {
  380.  
  381.         /* report header */
  382.         fprintf(stderr, "MEMORY WALL-CHECK (%s)", msg);
  383.         if (file)
  384.             fprintf(stderr, " from `%s' (%lu)", file, line);
  385.         fprintf(stderr, "\n");
  386.  
  387.         /* check all elements */
  388.         while (umem) {
  389.  
  390.             if (umem->ptr) {
  391.                 ugly_walldamaged(umem);
  392.                 umem = umem->next;
  393.             } else {
  394.                 umem = NULL;
  395.                 fprintf(stderr, "##\n## panic: memory list trashed\n##\n");
  396.             }
  397.         }
  398.     }
  399. }
  400.  
  401. /*
  402.  *-------------------------------------
  403.  * memory statistics functions
  404.  *-------------------------------------
  405.  */
  406.  
  407. /*
  408.  * ugly_mem_report
  409.  *
  410.  * displaly all memory nodes currently allocated
  411.  */
  412. void uglymem_report(STRPTR msg, STRPTR file, ULONG line, STRPTR date, STRPTR time)
  413. {
  414.     UGLYMEM *umem = first;
  415.  
  416.     if (umem) {
  417.  
  418.         /* report header */
  419.         fprintf(stderr, "MEMORY REPORT (%s)\n", msg);
  420.         if (file)
  421.             fprintf(stderr, "(\"%s\" (%lu), at %s, %s)\n",
  422.                     file, line, date, time);
  423.  
  424.         /* print all elements */
  425.         while (umem) {
  426.  
  427.             if (umem->ptr) {
  428.                 umem_info(umem);
  429.                 ugly_memdump(umem->ptr, umem->size);
  430.                 umem = umem->next;
  431.             } else {
  432.                 umem = NULL;
  433.                 fprintf(stderr, "##\n## panic: memory list trashed\n##\n");
  434.             }
  435.         }
  436.     }
  437. }
  438.  
  439. /*
  440.  * ugly_mem_stats
  441.  *
  442.  * display memory statistics (nodes & size allocated)
  443.  */
  444. void uglymem_stats(STRPTR msg, STRPTR file, ULONG line, STRPTR date, STRPTR time)
  445. {
  446.     /* statistics header */
  447.     fprintf(stderr, "MEMORY STATISTICS (%s)\n", msg);
  448.     if (file)
  449.         fprintf(stderr, "(\"%s\" (%lu), at %s, %s)\n",
  450.                 file, line, date, time);
  451.  
  452.     /* memory statistics */
  453.     fprintf(stderr, "  bytes used: %lu max: %lu/%lu  ",
  454.             ugly_curmem_usage, ugly_real_maxmem_usage,
  455.             ugly_maxmem_usage);
  456.     if (ugly_maxmem_usage)
  457.         fprintf(stderr, "slack: %lu%%\n",
  458.                 (100 * (ugly_real_maxmem_usage - ugly_maxmem_usage))
  459.                 / ugly_maxmem_usage);
  460.     else
  461.         fprintf(stderr, "no slack\n");
  462.     fprintf(stderr, "  nodes used: %lu (max: %lu)\n",
  463.             ugly_curnod_usage, ugly_maxnod_usage);
  464.     fprintf(stderr, "  calls to: umalloc(%lu)   ufree(%lu)\n",
  465.             ugly_umalloc_count, ugly_ufree_count);
  466.  
  467. }
  468.  
  469. /*
  470.  *-------------------------------------
  471.  * atexit functions
  472.  *-------------------------------------
  473.  */
  474.  
  475. /*
  476.  * atexit_uglymemory_real
  477.  */
  478. void atexit_uglymemory_real(void)
  479. {
  480.     ULONG mem_lost = ugly_curmem_usage;
  481.     uglymem_report("at exit:  MEMORY LEAK detected!",
  482.                    NULL, 0, NULL, NULL);
  483.     uglymem_stats("[exit]", NULL, 0, NULL, NULL);
  484.  
  485.     /* release all lost mem */
  486.     while (first)
  487.         del_uglymem(first);
  488.  
  489.     if (mem_lost)
  490.         fprintf(stderr, "\n%lu bytes of memory lost!\n", mem_lost);
  491. }
  492.  
  493. /*
  494.  * atexit_uglymemory_dummy
  495.  */
  496. void atexit_uglymemory_dummy(void)
  497. {
  498.     /* do nufin */
  499. }
  500.  
  501. /*
  502.  *-------------------------------------
  503.  * memory handling functions
  504.  *-------------------------------------
  505.  */
  506.  
  507. /*
  508.  * ugly_malloc_notracking
  509.  */
  510. void *ugly_malloc_notracking(size_t size)
  511. {
  512.     void *mem;
  513.     BOOL retry;
  514.  
  515.     do {
  516.  
  517.         mem = malloc(size);
  518.         if (!mem && ugly_nomem_handler) {
  519.  
  520.             /* call nomem-handler */
  521.             retry = (*ugly_nomem_handler) (size);
  522.             if (!retry)
  523.                 exit(EXIT_FAILURE);     /* abort programm */
  524.  
  525.         } else
  526.             retry = FALSE;
  527.  
  528.     } while (retry);
  529.  
  530.     return (mem);
  531. }
  532.  
  533. /*
  534.  * ugly_malloc_tracking
  535.  */
  536. void *ugly_malloc_tracking(size_t size, STRPTR file, ULONG line)
  537. {
  538.     void *mem = NULL;
  539.     UGLYMEM *umem = NULL;
  540.  
  541. #if DEBUG_UGLY_MEMORY==2
  542.     fprintf(stderr, "*memory* UMALLOC() from `%s' (%lu)\n", file, line);
  543. #endif
  544.     if (size) {
  545.  
  546.         /* update num. of calls to umalloc() */
  547.         ugly_umalloc_count++;
  548.  
  549.         /* alloc new uglymem */
  550.         umem = new_uglymem(size, file, line);
  551.         if (umem) {
  552.  
  553.             mem = umem->ptr;
  554.  
  555.             /* update memory usage and num of nodes */
  556.             ugly_curmem_usage += size;
  557.             ugly_real_curmem_usage += modfit(size, UMEM_BLOCKSIZE);
  558.             if (ugly_curmem_usage > ugly_maxmem_usage)
  559.                 ugly_maxmem_usage = ugly_curmem_usage;
  560.             if (ugly_real_curmem_usage > ugly_real_maxmem_usage)
  561.                 ugly_real_maxmem_usage = ugly_real_curmem_usage;
  562.             ugly_curnod_usage++;
  563.             if (ugly_curnod_usage > ugly_maxnod_usage)
  564.                 ugly_maxnod_usage = ugly_curnod_usage;
  565.  
  566.         }
  567.     } else {
  568.  
  569.         /* zero-alloc */
  570.  
  571.         /* update num. of failed calls to umalloc() */
  572.         ugly_umalloc_count_fail++;
  573.  
  574.         uglymem_message("MALLOC: zero-sized allocation");
  575.         uglymem_meminfo(NULL, file, line);
  576.  
  577.     }
  578.  
  579.     return (mem);
  580. }
  581.  
  582. /*
  583.  * ugly_free
  584.  */
  585. void ugly_free(void *ptr, STRPTR file, ULONG line)
  586. {
  587. #if DEBUG_UGLY_MEMORY==2
  588.     fprintf(stderr, "*memory* UFREE() from `%s' (%lu)\n", file, line);
  589. #endif
  590.     if (ptr) {
  591.  
  592.         UGLYMEM *umem = find_umem(ptr);
  593.  
  594.         if (umem) {
  595.  
  596.             /* update num. of calls to ufree() */
  597.             ugly_ufree_count++;
  598.  
  599.             /* update memory usage */
  600.             ugly_curmem_usage -= umem->size;
  601.             ugly_real_curmem_usage -= modfit(umem->size, UMEM_BLOCKSIZE);
  602.  
  603.             /* remove node from mem-list */
  604.             del_uglymem(umem);
  605.             ugly_curnod_usage--;
  606.  
  607.         } else {
  608.  
  609.             /* ptr has never been allocated */
  610.  
  611.             /* update num. of calls to ufree() */
  612.             ugly_ufree_count_fail++;
  613.  
  614.             /* -> error message */
  615.             uglymem_message("*** FREE: memory never allocated");
  616.             uglymem_meminfo(ptr, file, line);
  617.         }
  618.     }
  619. }
  620.  
  621. /*
  622.  * ugly_realloc
  623.  */
  624. void *ugly_realloc(void *ptr, size_t size, STRPTR file, ULONG line)
  625. {
  626.     ugly_free(ptr, file, line); /* free old mem */
  627.     return (ugly_malloc_tracking(size, file, line));    /* alloc new mem */
  628. }
  629.  
  630. /*
  631.  * * ugly_calloc
  632.  */
  633. void *ugly_calloc(size_t count, size_t size, STRPTR file, ULONG line)
  634. {
  635.     /* alloc new mem */
  636.     void *mem = ugly_malloc_tracking(count * size, file, line);
  637.  
  638.     /* fill mem with zero */
  639.     if (mem)
  640.         memset(mem, 0, size * count);
  641.  
  642.     return (mem);
  643. }
  644.  
  645.